#include "cameraDriver.h"

wxDEFINE_EVENT(EVT_FILE_ERROR, wxCommandEvent);

void GX_STDC OnFrameCallbackFun(GX_FRAME_CALLBACK_PARAM* pFrame)
{
	//在这里捕获绑定的cameraDevice对象
	cameraDriver::cameraDevice* CDevicePtr =(cameraDriver::cameraDevice*)pFrame->pUserParam;

	if (pFrame->status == GX_FRAME_STATUS_SUCCESS)
	{
		unsigned char* ImgDataPtr=new unsigned char[pFrame->nImgSize];
		std::memcpy(ImgDataPtr,pFrame->pImgBuf,pFrame->nImgSize);
		if(CDevicePtr->UpdateTimestamp)
		{
			CDevicePtr->startCollegeTime=std::chrono::steady_clock::now();
			CDevicePtr->UpdateTimestamp=false;
		}
		auto dtime=std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - CDevicePtr->startCollegeTime);
		CDevicePtr->ImageQueue.push({
			//std::vector<unsigned char>((unsigned char*)pFrame->pImgBuf, (unsigned char*)(pFrame->pImgBuf) + pFrame->nImgSize),
			ImgDataPtr,
			pFrame->nWidth,
			pFrame->nHeight,
			pFrame->nPixelFormat,
			pFrame->nFrameID,
			(uint64_t)dtime.count()
		});
	}
}

cameraDriver::cameraDriver()
{
	GX_STATUS status = GX_STATUS_SUCCESS;
	status = GXInitLib();
	if (status != GX_STATUS_SUCCESS)
		throw std::exception();
}

cameraDriver::~cameraDriver()
{
	GXCloseLib();
}

std::vector<DeviceInf> cameraDriver::GetDeviceList()
{
	std::vector<DeviceInf> DeviceList = {};
	GX_STATUS status = GX_STATUS_SUCCESS;
	uint32_t nDeviceNum = 0;  //获取设备数量
	GXSTAT_check(GXUpdateDeviceList(&nDeviceNum, 100)); //第二个参数为超时时间
	if (nDeviceNum > 0)
	{
		DeviceList.resize(nDeviceNum);
		GX_DEVICE_BASE_INFO* pBaseInfo = new GX_DEVICE_BASE_INFO[nDeviceNum];
		size_t nSize = nDeviceNum * sizeof(GX_DEVICE_BASE_INFO);
		GXSTAT_check(GXGetAllDeviceBaseInfo(pBaseInfo, &nSize));
		int deviceCount = 0;
		for (DeviceInf& i : DeviceList)
		{
			i.DeviceID = pBaseInfo[deviceCount].szDeviceID;
			i.VendorName = pBaseInfo[deviceCount].szVendorName;
			i.ModelName = pBaseInfo[deviceCount].szModelName;
			i.SN = pBaseInfo[deviceCount].szSN;
			i.DisplayName = pBaseInfo[deviceCount].szDisplayName;
			i.UserID = pBaseInfo[deviceCount].szUserID;
			switch (pBaseInfo[deviceCount].deviceClass)
			{
			case GX_DEVICE_CLASS_UNKNOWN:
				i.deviceLinkType = DeviceLinkType::Unknow;
			case GX_DEVICE_CLASS_USB2:
				i.deviceLinkType = DeviceLinkType::USB2_0;
			case GX_DEVICE_CLASS_GEV:
				i.deviceLinkType = DeviceLinkType::Network;
			case GX_DEVICE_CLASS_U3V:
				i.deviceLinkType = DeviceLinkType::USB3_0;
			}
			deviceCount++;
		}
		delete[] pBaseInfo;
	}
	return DeviceList;
}

std::list<cameraDriver::cameraDevice>::iterator cameraDriver::OpenIndexCamera(unsigned device, wxEvtHandler* evtHandler,int wxID)
{
	std::stringstream toNum;
	toNum << device;
	cameraList.emplace_back(toNum.str(), CameraOpenMode::INDEX, evtHandler,wxID); //原位构造，解决无法使用拷贝构造函数问题
	return std::prev(cameraList.end());
}

void cameraDriver::RemoveCamera(std::list<cameraDevice>::iterator itemPtr)
{
	cameraList.erase(itemPtr);
}

cameraDriverException::cameraDriverException(GX_STATUS status) : _status(status),userMsg(false)
{}

cameraDriverException::cameraDriverException(std::string str) : msg(str),userMsg(true)
{}

const char* cameraDriverException::what() const throw()
{
  if(userMsg)
  {
    return msg.c_str();
  }
  else
  {
	  switch (_status)
	  {
	  case GX_STATUS_SUCCESS:
	  	return "成功";
	  	break;
	  case GX_STATUS_ERROR:
	  	return "不期望发生的未明确内部错误";
	  	break;
	  case GX_STATUS_NOT_FOUND_TL:
	  	return "找不到TL库";
	  	break;
	  case GX_STATUS_NOT_FOUND_DEVICE:
	  	return "找不到设备";
	  	break;
	  case GX_STATUS_OFFLINE:
	  	return "当前设备为掉线状态";
	  	break;
	  case GX_STATUS_INVALID_PARAMETER:
	  	return "无效参数";
	  	break;
	  case GX_STATUS_INVALID_HANDLE:
	  	return "无效句柄";
	  	break;
	  case GX_STATUS_INVALID_CALL:
	  	return "无效的接口调用";
	  	break;
	  case GX_STATUS_INVALID_ACCESS:
	  	return "功能当前不可访问或设备访问模式错误";
	  	break;
	  case GX_STATUS_NEED_MORE_BUFFER:
	  	return "用户申请的buffer不足:读操作时用户输入buffersize小于实际需要";
	  	break;
	  case GX_STATUS_ERROR_TYPE:
	  	return "用户使用的FeatureID类型错误";
	  	break;
	  case GX_STATUS_OUT_OF_RANGE:
	  	return "用户写入的值越界";
	  	break;
	  case GX_STATUS_NOT_IMPLEMENTED:
	  	return "当前不支持的功能";
	  	break;
	  case GX_STATUS_NOT_INIT_API:
	  	return "没有调用初始化接口";
	  	break;
	  case GX_STATUS_TIMEOUT:
	  	return "超时错误";
	  	break;
	  default:
	  	return "未知错误";
	  	break;
	  }
  }
}

cameraDriver::cameraDevice::cameraDevice(std::string device, CameraOpenMode mode, wxEvtHandler* evtHandler,int _wxID) :
	_evtHandler(evtHandler),
	ImageCollegeStatus(false),
	ImageSaveStatus(false),
	ImageQueue(1000),
	wxID(_wxID),
	mtSave(evtHandler)
{
	hDevice = nullptr;
	GX_OPEN_PARAM stOpenParam;
	//独占方式打开
	stOpenParam.accessMode = GX_ACCESS_EXCLUSIVE;
	char content[512];
	memcpy(content, device.c_str(), device.length()+1);
	stOpenParam.pszContent = content;
	switch (mode)
	{
	case cameraDriver::CameraOpenMode::INDEX:
		stOpenParam.openMode = GX_OPEN_INDEX;
		break;
	case cameraDriver::CameraOpenMode::SN:
		stOpenParam.openMode = GX_OPEN_SN;
		break;
	case cameraDriver::CameraOpenMode::IP:
		stOpenParam.openMode = GX_OPEN_IP;
		break;
	case cameraDriver::CameraOpenMode::MAC:
		stOpenParam.openMode = GX_OPEN_MAC;
		break;
	}
	GXSTAT_check(GXOpenDevice(&stOpenParam, &hDevice));
	CreateThread();
}

cameraDriver::cameraDevice::~cameraDevice()
{
	if (ImageCollegeStatus.load())
		StopCollegeImage();
	if (ImageSaveStatus.load())
		StopSaveImage();
	RecoveryThread();
	GXCloseDevice(hDevice);
}

void cameraDriver::cameraDevice::StartCollegeImage()
{
	//这里传入第二个参数，用户私有数据指针，这样就能把处理函数绑定到对象中了
	//GXSTAT_check(GXRegisterCaptureCallback(hDevice, this, OnFrameCallbackFun));
	//GXSTAT_check(GXSendCommand(hDevice, GX_COMMAND_ACQUISITION_START));
	if(ImageTiggerMode)
	//触发采集，line0，上升沿
	{
		//设置触发模式为ON
		GXSTAT_check(GXSetEnum(hDevice,GX_ENUM_TRIGGER_MODE, GX_TRIGGER_MODE_ON));
		//设置触发激活方式为上升沿
		GXSTAT_check(GXSetEnum(hDevice,GX_ENUM_TRIGGER_ACTIVATION,GX_TRIGGER_ACTIVATION_RISINGEDGE));
		//触发方式Line0
		GXSTAT_check(GXSetEnum(hDevice, GX_ENUM_TRIGGER_SOURCE, GX_TRIGGER_SOURCE_LINE0));
	}
	else
		GXSTAT_check(GXSetEnum(hDevice,GX_ENUM_TRIGGER_MODE, GX_TRIGGER_MODE_OFF));
	GXSTAT_check(GXStreamOn(hDevice));
	ImageCollegeStatus.store(true); //激活图像接收线程
	zero_copyCollege=new CameraCollegeZeroCopy(&hDevice,&ImageQueue,5);
  imageFormat=GetImageFormat(); //获取图像格式
	ClearCounter();
  if(imageFormat==pixelFormat::Other)
  {
    throw cameraDriverException("不支持的图像格式");
  }
}

void cameraDriver::cameraDevice::StopCollegeImage()
{
	if (ImageCollegeStatus.load())
	{
		delete zero_copyCollege;
		zero_copyCollege=nullptr;
		ImageCollegeStatus.store(false);
		GXSTAT_check(GXStreamOff(hDevice));
		//GXSendCommand(hDevice, GX_COMMAND_ACQUISITION_STOP);
		//GXUnregisterCaptureCallback(hDevice);
	}
}

void cameraDriver::cameraDevice::CreateThread()
{
	if (ThreadRunFlag.load() == true)
		//说明已经有一个线程了
		throw std::exception();
	ThreadRunFlag.store(true);
	lastEmitSignalTime = std::chrono::steady_clock::now(); //初始化一下
	HandleImageThread = std::async(std::launch::async, std::function<void(cameraDevice*)>(&cameraDevice::ThreadHandleFrame),this);
	if (HandleImageThread.valid() == false) throw std::exception();
}

void cameraDriver::cameraDevice::RecoveryThread()
{
	ThreadRunFlag.store(false);
	ImageQueue.StopThreadWait();
	//等待线程退出
	if(HandleImageThread.valid())
		HandleImageThread.get();
}

#include "ImageDisplay.h"
void cameraDriver::cameraDevice::ThreadHandleFrame()
{
	//可能队列里还有旧的数据在上一次处理中没有全部处理完
	ImageQueue.SetPushEnable(true);

	while (ThreadRunFlag.load())
	{
		FrameData frame = ImageQueue.pop();
		imageWidth = frame.ImgWidth;
		imageHeight = frame.ImgHeight;
		using namespace std::chrono;
		auto nowTime = steady_clock::now();
		if (ImageCollegeStatus.load())
		{
			if (duration_cast<milliseconds>(nowTime - lastEmitSignalTime).count()>=2)  //控制帧率，30FPS
			{
				lastEmitSignalTime = nowTime;
				//异步调用锁，保证ImageDisplay不会提前析构掉
				std::lock_guard lckAsync(((ImageDisplay*)_evtHandler)->mutAsyncing);
				if (!(((ImageDisplay*)_evtHandler)->atomExists.load())) return;
				((ImageDisplay*)_evtHandler)->showImage(frame.pImageData,frame.ImgWidth,frame.ImgHeight,imageFormat);
			}
		}
		if (ImageSaveStatus.load())  //图像存储
		{
			try
			{
				mtSave.SaveImage(frame.pImageData,frame.Timestamp);
			}
			catch(...)
			{
				_evtHandler->QueueEvent(new wxCommandEvent(EVT_FILE_ERROR,wxID));
				ThreadRunFlag.store(false);
				ImageQueue.SetPushEnable(false); //阻止新的数据上来
				return;
			}
		}
		//释放图片
		delete[] frame.pImageData;
		HandleTime = duration_cast<microseconds>(steady_clock::now() - nowTime).count();
		ReceiveImageNum++;
	}
	ImageQueue.SetPushEnable(false); //阻止新的数据上来
}

bool cameraDriver::cameraDevice::GetCollegeImageStatus()
{
	return ImageCollegeStatus.load();
}

void cameraDriver::cameraDevice::SetImageSavePath(std::string path)
{
	//规避数据竞争
	if (ImageSaveStatus.load() == true)
		throw std::exception();
	ImageSavePath = path;
}

std::string cameraDriver::cameraDevice::StartSaveImage()
{
	if (ImageSavePath.empty())
		throw std::exception();
	//saveFile.SetSavePath(ImageSavePath);
	//std::string fileName=saveFile.StartInputImage(imageWidth,imageHeight);
	std::string fileName;
	try
	{
		fileName=mtSave.StartSaveImage(ImageSavePath,imageWidth,imageHeight,imageFormat);
	}
	catch(...)
	{
		_evtHandler->QueueEvent(new wxCommandEvent(EVT_MULTIWRITE_ERR,wxID_ANY));
		return fileName;
	}
	UpdateTimestamp=true;
	//ResetTimestamp();
	ImageSaveStatus.store(true);
	return fileName;
}

void cameraDriver::cameraDevice::StopSaveImage()
{
	ImageSaveStatus.store(false);
	//saveFile.StopInputImage();
	mtSave.StopSaveImage();
}

bool cameraDriver::cameraDevice::GetSaveImageStatus()
{
	return ImageSaveStatus.load();
}

unsigned char* ImgPixel8bitTo24bit(const std::vector<unsigned char>& rawImg)
{
	unsigned char* imageData = new unsigned char[rawImg.size() * 3];
	unsigned char* img24BitPtr = &imageData[0];
	auto img8BitPtr = rawImg.begin();
	for (; img8BitPtr != rawImg.end(); img8BitPtr++, img24BitPtr++)
	{
		*img24BitPtr = *img8BitPtr;
		img24BitPtr++;
		*img24BitPtr = *img8BitPtr;
		img24BitPtr++;
		*img24BitPtr = *img8BitPtr;
	}
	return imageData;
}

void cameraDriver::CloseCamera(std::list<cameraDevice>::iterator devicePtr)
{
	cameraList.erase(devicePtr);
}

void cameraDriver::cameraDevice::SetEvtHandler(wxEvtHandler* c)
{
	_evtHandler = c;
}

void cameraDriver::cameraDevice::SetExposureTime(double time)
{
	GXSTAT_check(GXSetFloat(hDevice, GX_FLOAT_EXPOSURE_TIME, time));
}

double cameraDriver::cameraDevice::GetExposureTime()
{
	double dValue;
	GXSTAT_check(GXGetFloat(hDevice, GX_FLOAT_EXPOSURE_TIME, &dValue));
	return dValue;
}

int64_t cameraDriver::cameraDevice::GetSensorHeight()
{
	int64_t nValue;
	GXSTAT_check(GXGetInt(hDevice, GX_INT_SENSOR_HEIGHT, &nValue));
	return nValue;
}

int64_t cameraDriver::cameraDevice::GetSensorWidth()
{
	int64_t nValue;
	GXSTAT_check(GXGetInt(hDevice, GX_INT_SENSOR_WIDTH, &nValue));
	return nValue;
}

void cameraDriver::cameraDevice::SetImageHeight(int64_t value)
{
	//GXSTAT_check(GXSendCommand(hDevice, GX_COMMAND_ACQUISITION_STOP));
	GXSTAT_check(GXSetInt(hDevice, GX_INT_HEIGHT, value));
	//GXSTAT_check(GXSendCommand(hDevice, GX_COMMAND_ACQUISITION_START));
}

void cameraDriver::cameraDevice::SetImageWidth(int64_t value)
{
	//GXSTAT_check(GXSendCommand(hDevice, GX_COMMAND_ACQUISITION_STOP));
	GXSTAT_check(GXSetInt(hDevice, GX_INT_WIDTH, value));
	//GXSTAT_check(GXSendCommand(hDevice, GX_COMMAND_ACQUISITION_START));
}

int64_t cameraDriver::cameraDevice::GetImageHeight()
{
	int64_t value;
	GXSTAT_check(GXGetInt(hDevice, GX_INT_HEIGHT, &value));
	return value;
}

int64_t cameraDriver::cameraDevice::GetImageWidth()
{
	int64_t value;
	GXSTAT_check(GXGetInt(hDevice, GX_INT_WIDTH, &value));
	return value;
}

void cameraDriver::cameraDevice::SetImageOffsetX(int64_t value)
{
	GXSTAT_check(GXSetInt(hDevice, GX_INT_OFFSET_X, value-value%8));
}

void cameraDriver::cameraDevice::SetImageOffsetY(int64_t value)
{
	GXSTAT_check(GXSetInt(hDevice, GX_INT_OFFSET_Y, value-value%2));
}

int64_t cameraDriver::cameraDevice::GetImageOffsetX()
{
	int64_t value;
	GXSTAT_check(GXGetInt(hDevice, GX_INT_OFFSET_X, &value));
	return value;
}

int64_t cameraDriver::cameraDevice::GetImageOffsetY()
{
	int64_t value;
	GXSTAT_check(GXGetInt(hDevice, GX_INT_OFFSET_Y, &value));
	return value;
}

double cameraDriver::cameraDevice::GetCollegeFrameRate()
{
	double value;
	GXSTAT_check(GXGetFloat(hDevice, GX_FLOAT_CURRENT_ACQUISITION_FRAME_RATE, &value));
	return value;
}

void cameraDriver::cameraDevice::ClearCounter()
{
	UnableSaveImageNum.store(0);
	ReceiveImageNum.store(0);
}

unsigned int cameraDriver::cameraDevice::GetUnableSaveImageNum()
{
	return UnableSaveImageNum.load();
}

unsigned int cameraDriver::cameraDevice::GetReceiveImageNum()
{
	return ReceiveImageNum.load();
}

unsigned int cameraDriver::cameraDevice::GetHandleTime()
{
	return HandleTime.load();
}

unsigned int cameraDriver::cameraDevice::GetQueueLength()
{
	return ImageQueue.GetSize();
}

void cameraDriver::cameraDevice::SetLinkLimit(bool value)
{
	if (value)
		GXSTAT_check(GXSetEnum(hDevice, GX_ENUM_DEVICE_LINK_THROUGHPUT_LIMIT_MODE, GX_DEVICE_LINK_THROUGHPUT_LIMIT_MODE_OFF));
	else
		GXSetEnum(hDevice, GX_ENUM_DEVICE_LINK_THROUGHPUT_LIMIT_MODE, GX_DEVICE_LINK_THROUGHPUT_LIMIT_MODE_ON);
}

int64_t cameraDriver::cameraDevice::GetLinkSpeed()
{
	int64_t value;
	GXSTAT_check(GXGetInt(hDevice, GX_INT_DEVICE_LINK_CURRENT_THROUGHPUT, &value));
	return value;
}

void cameraDriver::cameraDevice::ResetTimestamp()
{
	GXSTAT_check(GXSendCommand(hDevice,GX_COMMAND_TIMESTAMP_RESET));
}

unsigned cameraDriver::GetCameraCount()
{
	return cameraList.size();
}

void cameraDriver::cameraDevice::SetCmpAcceleration(int value)
{
	mtSave.SetCmpAcceleration(value);
}

void cameraDriver::cameraDevice::SetTriggerMode(bool value)
{
	ImageTiggerMode=value;
}

void cameraDriver::cameraDevice::SetImageFPSRate(long fps)
{
	GXSTAT_check(GXSetFloat(hDevice, GX_FLOAT_ACQUISITION_FRAME_RATE, fps));
}

void cameraDriver::cameraDevice::SetImageFPSControl(bool status)
{
	if(status)
		GXSTAT_check(GXSetEnum(hDevice, GX_ENUM_ACQUISITION_FRAME_RATE_MODE,GX_ACQUISITION_FRAME_RATE_MODE_ON));
	else
		GXSTAT_check(GXSetEnum(hDevice, GX_ENUM_ACQUISITION_FRAME_RATE_MODE,GX_ACQUISITION_FRAME_RATE_MODE_OFF));
}

bool cameraDriver::cameraDevice::GetTriggerMode()
{
	return ImageTiggerMode;
}

pixelFormat cameraDriver::cameraDevice::GetImageFormat()
{
  int64_t data;
  GXSTAT_check(GXGetEnum(hDevice,GX_ENUM_PIXEL_FORMAT,&data));
  switch(data)
  {
    case GX_PIXEL_FORMAT_MONO8:
      return pixelFormat::MONO8;
    case GX_PIXEL_FORMAT_BAYER_GR8:
      return pixelFormat::BAYER_GR8;
    case GX_PIXEL_FORMAT_BAYER_RG8:
      return pixelFormat::BAYER_RG8;
    case GX_PIXEL_FORMAT_BAYER_GB8:
      return pixelFormat::BAYER_GB8;
    case GX_PIXEL_FORMAT_BAYER_BG8:
      return pixelFormat::BAYER_BG8;
    default:
      return pixelFormat::Other;
  }
}

void cameraDriver::cameraDevice::SetImageFormat(pixelFormat format)
{
  switch (format) {
    case pixelFormat::MONO8:
      GXSTAT_check(GXSetEnum(hDevice,GX_ENUM_PIXEL_FORMAT,GX_PIXEL_FORMAT_MONO8));
      break;
    case pixelFormat::BAYER_BG8:
      GXSTAT_check(GXSetEnum(hDevice,GX_ENUM_PIXEL_FORMAT,GX_PIXEL_FORMAT_BAYER_BG8));
      break;
    case pixelFormat::BAYER_GB8:
      GXSTAT_check(GXSetEnum(hDevice,GX_ENUM_PIXEL_FORMAT,GX_PIXEL_FORMAT_BAYER_GB8));
      break;
    case pixelFormat::BAYER_RG8:
      GXSTAT_check(GXSetEnum(hDevice,GX_ENUM_PIXEL_FORMAT,GX_PIXEL_FORMAT_BAYER_RG8));
      break;
    case pixelFormat::BAYER_GR8:
      GXSTAT_check(GXSetEnum(hDevice,GX_ENUM_PIXEL_FORMAT,GX_PIXEL_FORMAT_BAYER_GR8));
      break;
    default:
      break;
  }
}
